Character Content

Now that we have declared the element content model, we need to declare the character content for those elements that contain character data.  When only text is allowed inside an element, we identify these elements as PCDATA (parseable character data) elements.  In effect, we are stipulating that elements of this type can only contain text, and not other elements.  This is similar in concept (but not as robust) as specifying a data type for a column (element).

The syntax for specifying a PCDATA element is:

<!ELEMENT name #PCDATA>

Notice the use of the # symbol.  This is to prevent confusion between the keyword and an acceptable name.  Let’s update our DTD to declare those elements that will contain PCDATA (text only).

<!DOCTYPE employees [
	<!ELEMENT employees ( employee+ )>

	<!ELEMENT employee (name, position, address, phone)>

	<!ELEMENT name (first, last)>
	<!ELEMENT first (#PCDATA)>
	<!ELEMENT last  (#PCDATA)>

	<!ELEMENT position (#PCDATA)>

	<!ELEMENT address (street?, city?, state?, zip?)>
	<!ELEMENT street (#PCDATA)>
	<!ELEMENT city   (#PCDATA)>
	<!ELEMENT state  (#PCDATA)>
	<!ELEMENT zip    (#PCDATA)>

	<!ELEMENT phone 
			(main, office*, fax*, mobile*, home*)>
	<!ELEMENT main   (#PCDATA)>
	<!ELEMENT office (#PCDATA)>
	<!ELEMENT fax    (#PCDATA)>
	<!ELEMENT mobile (#PCDATA)>
	<!ELEMENT home   (#PCDATA)>
]>

Tip:	Always remember that XML cannot deal with ambiguous content models.  Once you declare a DTD, you have to go all the way with it and declare everything!  This  includes elements that contain other elements, those that  only contain text, empty elements, and even element attributes as you shall soon see.

Notice that we declared our PCDATA elements directly under their parent elements.  While this is not necessary, it is a good practice as it makes your DTD’s more readable.  You could for example declare all of your PCDATA elements at the end, but the end result is very difficult to visually understand.

Now we have our element content model defined.  We have specified element relationships (parent/child/sibling), sequential order, required elements, optional elements, and multiple elements.  But there is still more to element declarations that we need to understand.

Element Choices

Let’s divert from our employee XML document example for a few minutes and discuss some of the other capabilities that are available when declaring elements.  We will come back to the employee example and complete our DTD shortly.

You now know how to declare elements and their content models provided that the elements contained therein are static (not changing).  But what if you have an or condition where you may want one element or another element, but never both?  This is handled using the or operator ( | ).  The syntax is:

<!ELEMENT name (option1 | option2)>

Let’s say that you have an element named <account> that must contain either a <checking> element, or a <savings> element.  The syntax would be as follows:

<!ELEMENT account (checking | savings)>

An <account> element must have either a <checking> element or a <savings> element, or the XML processor will generate an error.  

The following document provides an example of using optional elements :

<?xml version="1.0"?>
<!DOCTYPE accounts [
	<!ELEMENT accounts ( account+ )>
	<!ELEMENT account  ( checking | savings )>
	<!ELEMENT checking (#PCDATA)>
	<!ELEMENT savings  (#PCDATA)>
]>
<accounts>
	<account>
		<checking>Money Market</checking>
	</account>

	<account>
		<savings>SaverPlus</savings>
	</account>
</accounts>

File: Chapter 4\ElementsChoices.xml

Let’s take it a step further and add the balance to the <account> element too.  The new element <balance> would be required, while either the <checking> or <savings> element would be required.  The syntax for the new declaration would be:

<!ELEMENT account ((checking | savings), balance)>

Using the new element declaration, each <account> element would have a <checking> or <savings> element followed by a <balance> element.  

<?xml version="1.0"?>
<!DOCTYPE accounts [
	<!ELEMENT accounts ( account+ )>
	<!ELEMENT account ( (checking | savings), balance )>
	<!ELEMENT checking (#PCDATA)>
	<!ELEMENT savings  (#PCDATA)>
	<!ELEMENT balance  (#PCDATA)>
]>
<accounts>
	<account>
		<checking>Money Market</checking>
		<balance>$1,000</balance>
	</account>

	<account>
		<savings>SaverPlus</savings>
		<balance>$5,000</balance>
	</account>
</accounts>

File: Chapter 4\ElementChoices2.xml

Note that in the element declaration, the elements “checking” and “savings” are encapsulated within parenthesis.  This is so that the model makes sense when you look at it.  Also, some XML processors will generate warnings or errors because they interpret the model as ambiguous.

Tip:	Always use parenthesis to clearly define all conditions in your element model.  This will serve two purposes.  First, your DTD will be more understandable from a human aspect.  Second, XML processors will be able to interpret your DTD the way that you intended, reducing the number of possible mistakes.

The following syntax would be ambiguous and cause an error.

<!ELEMENT account ( checking | savings, balance )>

The XML processor can’t tell which would be correct:

The <account> element must have a <checking> element or <savings> and <balance> elements, or

The <account> element must have either a <checking> or <savings> element and always have a <balance> element.

Proper use of parenthesis solves the problem.  In the case of the first possible solution (either checking or savings and balance), we would define the element as follows:

<!ELEMENT account ( checking | (savings, balance) )>

In the case of the second possible solution (either checking or savings and always balance), we would define the element as follows:

<!ELEMENT account ( (checking | savings), balance )>

Remember, XML processors cannot deal with ambiguity.  You must clearly define your content model or you will get errors.